

use crate::data_frame::value::{ElementRealConfValue, ConfValue, ElementValue, RealValue};
use crate::physical_plan::{logicalplan_try_map_physicalplan, logical_plan_expr_try_map_physical_plan_expr};
use crate::conf_init::{MapErr, MapResult};
use crate::run_plan::func::{RunPlanExprFunc, RunPlanPhysicalPlanFuncArg, RunPlanExprFuncComb, RunPlanExprFuncCombWithName};
use sapeur::{Parser, parse_text, ParserResult};
use sapeur::text::{TextChar, text_key_world, text_just, text_ident, text_number, text_signed_number, text_number_float};
use sapeur::recursive::{Recursive, recursive};
use std::str::FromStr;
use sapeur::logical_comb::LogicalCombOutput;

/*
    可嵌套的通用函数表达
    第一层必须是函数，函数参数可以是Value或者其他函数
*/
#[derive(Debug,Clone)]
pub enum LogicalPlanExprFuncOrValue {
    Value(ElementRealConfValue),
    FuncWithValue(String, Vec<LogicalPlanExprFuncOrValue>),
}

pub fn parse_logical_expr_real_value<'a>()
    ->impl Parser<char, RealValue, TextChar>+'a {

    let parse_boolean_true = text_just("bool_true").map_end(|_o| RealValue::Boolean(true));
    let parse_boolean_false = text_just("bool_false").map_end(|_o| RealValue::Boolean(false));

    let parse_utf8 = text_just("utf8_").and(text_key_world())
        .map_end(|(_,o)| RealValue::Utf8(o));
    let parse_u64 = text_just("u64_").and(text_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = u64::from_str(o.as_str()){
                Some(RealValue::U64(u))
            }else{
                None
            }
        );

    let parse_i64 = text_just("i64_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = i64::from_str(o.as_str()){
                Some(RealValue::I64(u))
            }else{
                None
            }
        );

    let parse_f64 = text_just("f64").and(text_number_float())
        .map_end_option(|(_,o)|
            if let Ok(u) = f64::from_str(o.as_str()){
                Some(RealValue::F64(u))
            }else{
                None
            }
        );

    let parse_u32 = text_just("u32_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = u32::from_str(o.as_str()){
                Some(RealValue::U32(u))
            }else{
                None
            }
        );
    let parse_i32 = text_just("i32_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = i32::from_str(o.as_str()){
                Some(RealValue::I32(u))
            }else{
                None
            }
        );
    let parse_u16 = text_just("u16_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = u16::from_str(o.as_str()){
                Some(RealValue::U16(u))
            }else{
                None
            }
        );
    let parse_i16 = text_just("i16_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = i16::from_str(o.as_str()){
                Some(RealValue::I16(u))
            }else{
                None
            }
        );
    let parse_u8 = text_just("u8_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = u8::from_str(o.as_str()){
                Some(RealValue::U8(u))
            }else{
                None
            }
        );
    let parse_i8 = text_just("i8_").and(text_signed_number())
        .map_end_option(|(_,o)|
            if let Ok(u) = i8::from_str(o.as_str()){
                Some(RealValue::I8(u))
            }else{
                None
            }
        );

    parse_boolean_true
        .or(parse_boolean_false)
        .or(parse_utf8)
        .or(parse_u64)
        .or(parse_i64)
        .or(parse_f64)
        .or(parse_u32)
        .or(parse_i32)
        .or(parse_u16)
        .or(parse_i16)
        .or(parse_u8)
        .or(parse_i8)
}

pub fn parse_logical_expr_func_or_value_single<'a>()
    ->impl Parser<char, LogicalPlanExprFuncOrValue, TextChar>+'a {

    let recusive_parser: Recursive<'a,char, LogicalPlanExprFuncOrValue,TextChar> =

        recursive::<'a,char, LogicalPlanExprFuncOrValue,TextChar,_,_>(|parser| {

            let parse_just_real = parse_logical_expr_real_value()
                .map_end(|o|
                    LogicalPlanExprFuncOrValue::Value(ElementRealConfValue::RealValue(o))
                );

            let parse_just_element = text_key_world()
                .separated_by(text_just(",").expand_by_repeated(text_just(" ")), false)
                .delimited_by(text_just("(").expand_by_repeated(text_just(" ")), text_just(")").expand_by_repeated(text_just(" ")))
                .map_end(|o|
                    LogicalPlanExprFuncOrValue::Value(ElementRealConfValue::ElementValue(ElementValue::new(o)))
                );

            let parse_just_conf = text_key_world()
                .map_end(|o|
                    LogicalPlanExprFuncOrValue::Value(ElementRealConfValue::ConfValue(ConfValue::new(o)))
                );

            let parse_func_no_arg = text_ident()
                .then_ignore(text_just("(").expand_by_repeated(text_just(" ")))
                .then_ignore(text_just(")").expand_by_repeated(text_just(" ")))
                .map_end(|o| LogicalPlanExprFuncOrValue::FuncWithValue(o, Vec::new()));

            let parse_func_with_arg = text_ident().and(
                parser.clone()
                    .separated_by(text_just(",").expand_by_repeated(text_just(" ")), false)
                    .delimited_by(text_just("(").expand_by_repeated(text_just(" ")), text_just(")").expand_by_repeated(text_just(" ")))
            )
                .map_end(|(n,o)|
                    LogicalPlanExprFuncOrValue::FuncWithValue(n, o)
                );

            parse_just_real
                .or(parse_just_element)
                .or(parse_just_conf)
                .or(parse_func_no_arg)
                .or(parse_func_with_arg)
        });

    recusive_parser
}

pub fn parse_logical_expr_func_comb<'a>()
    ->impl Parser<char, LogicalCombOutput<LogicalPlanExprFuncOrValue>, TextChar>+'a{

    parse_logical_expr_func_or_value_single().logical_comb(
        text_just("(").expand_by_repeated(text_just(" ")),
        text_just(")").expand_by_repeated(text_just(" ")),
        text_just("&&").expand_by_repeated(text_just(" ")),
        text_just("||").expand_by_repeated(text_just(" "))
    )
}

pub fn conf_parse_logical_expr_func(desc: &str) ->MapResult<LogicalPlanExprFuncOrValue>{
    info!("conf_parse_logical_expr_func [{}]", desc);

    let res = parse_text(desc,
                         &parse_logical_expr_func_or_value_single(),
                         vec!["no"].as_slice());
    match res {
        ParserResult::OkEnd(t) => {
            return MapResult::Ok(t);
        },
        ParserResult::Ok(_) => {
            warn!("conf_parse_logical_expr_func failed: not to OkEnd");
            return MapResult::Err(MapErr::new(format!("[{}] parse Ok not to OkEnd", desc)));
        },
        ParserResult::Err(e) => {
            warn!("conf_parse_logical_expr_func failed: at offset {}", e.offset);
            return MapResult::Err(MapErr::new(format!("[{}] Err at offset [{}]",
                                                      desc, e.offset)))
        },
        ParserResult::ErrEnd(e) => {
            warn!("conf_parse_logical_expr_func failed: at offset {}", e.offset);
            return MapResult::Err(MapErr::new(format!("[{}] ErrEnd at offset [{}]",
                                                      desc, e.offset)))
        },
    }
}

pub fn conf_parse_logical_expr_func_comb(desc: &str)
    ->MapResult<LogicalCombOutput<LogicalPlanExprFuncOrValue>>{

    info!("conf_parse_logical_expr_func_comb [{}]", desc);

    let res = parse_text(desc,
                         &parse_logical_expr_func_comb(),
                         vec!["no"].as_slice());
    match res {
        ParserResult::OkEnd(t) => {
            return MapResult::Ok(t);
        },
        ParserResult::Ok(_) => {
            warn!("conf_parse_logical_expr_func failed: not to OkEnd");
            return MapResult::Err(MapErr::new(format!("[{}] parse Ok not to OkEnd", desc)));
        },
        ParserResult::Err(e) => {
            warn!("conf_parse_logical_expr_func failed: at offset {}", e.offset);
            return MapResult::Err(MapErr::new(format!("[{}] Err at offset [{}]",
                                                      desc, e.offset)))
        },
        ParserResult::ErrEnd(e) => {
            warn!("conf_parse_logical_expr_func failed: at offset {}", e.offset);
            return MapResult::Err(MapErr::new(format!("[{}] ErrEnd at offset [{}]",
                                                      desc, e.offset)))
        },
    }
}

pub fn logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(conf: &LogicalCombOutput<LogicalPlanExprFuncOrValue>)
        ->MapResult<Box<RunPlanExprFuncComb>>{

    info!("logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb");
    match &conf{
        LogicalCombOutput::Single(arg) => {
            let tmp = logical_plan_expr_func_map_to_run_plan_expr_func(arg)?;
            return MapResult::Ok(Box::new(RunPlanExprFuncComb::Single(tmp)));
        },
        LogicalCombOutput::And(left,right) => {
            return MapResult::Ok(Box::new(RunPlanExprFuncComb::And(
                logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(left)?,
                logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(right)?
            )));
        },
        LogicalCombOutput::Or(left,right) => {
            return MapResult::Ok(Box::new(RunPlanExprFuncComb::Or(
                logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(left)?,
                logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(right)?
            )));
        },
    }
}

pub fn logical_plan_expr_func_map_to_run_plan_expr_func(conf: &LogicalPlanExprFuncOrValue)
    ->MapResult<Box<RunPlanExprFunc>>{

    match conf{
        LogicalPlanExprFuncOrValue::Value(_) => {
            return Err(MapErr::new(format!("need func here")));
        },
        LogicalPlanExprFuncOrValue::FuncWithValue(n, args) => {
            let physical_func = logicalplan_try_map_physicalplan(n.as_str())?;
            let mut value_list = Vec::new();
            for arg in args.iter(){
                match &arg{
                    LogicalPlanExprFuncOrValue::Value(arg) => {
                        let physical_expr = logical_plan_expr_try_map_physical_plan_expr(arg);
                        value_list.push(RunPlanPhysicalPlanFuncArg::Normal(physical_expr));
                    },
                    LogicalPlanExprFuncOrValue::FuncWithValue(_, _) => {
                        let other_func = logical_plan_expr_func_map_to_run_plan_expr_func(&arg)?;
                        value_list.push(RunPlanPhysicalPlanFuncArg::OtherRunPlan(other_func));
                    },
                }
            }

            return Ok(RunPlanExprFunc::new(physical_func, value_list));
        },
    }
}

pub fn logical_plan_expr_func_map_to_run_plan(desc: &str)->MapResult<Box<RunPlanExprFunc>>{
    info!("logical_plan_expr_func_map_to_run_plan");
    let func = conf_parse_logical_expr_func(desc)?;
    let func = logical_plan_expr_func_map_to_run_plan_expr_func(&func)?;
    return MapResult::Ok(func);
}

pub fn logical_plan_expr_func_comb_map_to_run_plan(name: &str, desc: &str)
    ->MapResult<Box<RunPlanExprFuncCombWithName>>{

    let func_comb = conf_parse_logical_expr_func_comb(desc)?;
    let func_comb = logical_plan_expr_func_comb_map_to_run_plan_expr_func_comb(&func_comb)?;
    let func_comb_with_name = Box::new(
        RunPlanExprFuncCombWithName{
            name: name.to_string(),
            func_comb: func_comb,
        }
    );
    return MapResult::Ok(func_comb_with_name);
}

